import uuid
from datetime import timedelta, datetime
import oss2
from django.contrib.auth import get_user_model, authenticate
from django.contrib.auth.hashers import make_password
from django.core.files.storage.filesystem import FileSystemStorage
from django.db.models import Sum, Count, Max, Avg
from django.utils import timezone
from rest_framework import viewsets, mixins, status
from rest_framework.authtoken.models import Token
from rest_framework.response import Response

from bilimili_django import settings
from comment.models import Comment
from favor.models import Favor
from follow.models import Follow
from like.models import Like
from play.models import Play
from video.models import Videos
from .models import UserProfile
from .serializer import UserSerializer, UserRegisterSerializer, UserLoginSerializer

User = get_user_model()


# Create your views here.
class UserViewSet(viewsets.ModelViewSet):
    serializer_class = UserSerializer

    def get_queryset(self):
        queryset = UserProfile.objects.all()
        params = self.request.query_params
        if params:
            filters = {}
            for key, value in params.items():
                filters[key] = value
            queryset = queryset.filter(**filters)
        return queryset

    def get_user_info(self, request, *args, **kwargs):
        user = kwargs.get('user_id')
        user = UserProfile.objects.get(id=user)
        result = UserSerializer(user).data
        fans = Follow.objects.filter(mup=user).filter(is_active=True).count()
        attract = Follow.objects.filter(fan=user).filter(is_active=True).count()
        result.update({"fans": fans, "attract": attract})
        return Response(result, status=status.HTTP_200_OK)

    def get_create_data(self, request, *args, **kwargs):
        user = kwargs.get('user_id')
        date_op = kwargs.get('date_op')
        videos = Videos.objects.filter(mup_id=user)
        today = timezone.now().date()
        all_date = datetime(2000, 1, 1)
        reflect = {'7日内': 0, '30日内': 1, '累计': 2}
        date_ops = [today - timedelta(days=7), today - timedelta(days=30),
                    all_date]
        data = {
            'play_count':
                Play.objects.filter(video__in=videos).filter(time__gte=date_ops[reflect.get(date_op)]).aggregate(
                    sumPlays=Sum('count'))['sumPlays'],
            'like_count':
                Like.objects.filter(video_id__in=videos).filter(time__gte=date_ops[reflect.get(date_op)]).filter(
                    is_active=True).count(),
            'favor_count':
                Favor.objects.filter(video_id__in=videos).filter(time__gte=date_ops[reflect.get(date_op)]).filter(
                    is_active=True).count(),
            'fan_add':
                Follow.objects.filter(mup=user).filter(time__gte=date_ops[reflect.get(date_op)]).filter(
                    is_active=True).count(),
            'comment_count':
                Comment.objects.filter(video__in=videos).filter(time__gte=date_ops[reflect.get(date_op)]).count()
        }
        return Response(data, status=status.HTTP_200_OK)

    def get_search_result(self, request, *args, **kwargs):
        name = request.query_params.get('name')
        page = int(request.query_params.get('page', 0))

        if not name:
            return Response({'users': [], 'total_count': 0}, status=status.HTTP_200_OK)

        start_index = page * 24
        end_index = start_index + 24

        users = UserProfile.objects.filter(username__icontains=name).values('username', 'avatar_path',
                                                                            'description', 'id')
        total_count = users.count()
        if start_index >= total_count:
            return Response({'users': [], 'total_count': total_count}, status=status.HTTP_200_OK)
        elif end_index > total_count:
            end_index = total_count

        results = list(users[start_index:end_index])
        return Response({'users': results, 'total_count': total_count}, status=status.HTTP_200_OK)

    def get_chart_data(self, request, *args, **kwargs):
        user = kwargs.get('user_id')
        date_op = kwargs.get('date_op')
        choice = kwargs.get('choice')
        choice_op = ['播放量', '点赞量', '收藏量', '净增粉丝', '评论量']
        data = get_data(user, date_op, choice)

        return Response({'data': data, 'name': choice_op[choice]}, status=status.HTTP_200_OK)

    def get_mup_data(self, request, *args, **kwargs):
        user = kwargs.get('mup_id')
        result = []
        fans = Follow.objects.filter(mup=user).filter(is_active=True).values('fan')
        videos = Videos.objects.filter(mup=user).filter(status=True).order_by('-update_time')
        for video in videos:
            data = serialize_data(video, fans)
            result.append(data)
        return Response({'data': result}, status=status.HTTP_200_OK)

    def modify_user(self, request, *args, **kwargs):
        uid = request.data['user_id']
        user = UserProfile.objects.get(id=uid)
        Update_user = UserProfile.objects.filter(id=uid)
        if 'password' in request.data:
            new_password = make_password(request.data['password'])
            Update_user.update(password=new_password)
        if 'username' in request.data and request.data['username'] != user.username:
            new_username = request.data['username']
            try:
                Update_user.update(username=new_username)
            except:
                return Response(status=status.HTTP_400_BAD_REQUEST)
        if 'description' in request.data:
            new_description = request.data['description']
            Update_user.update(description=new_description)
        # avatar_path = user.values_list('avatar_path', flat=True).first()
        if 'file' in request.FILES:
            filename = user.username + '.png'
            local_write_path = 'vue/bilimili/src/assets/imgs/avatars/' + filename
            avatar_read = settings.OSS_READ_ROOT + '/imgs/avatars/' + filename
            fs = FileSystemStorage(location='vue/bilimili/src/assets/imgs/avatars/')
            fs.save(filename, request.FILES['file'])
            bucket = oss2.Bucket(settings.AUTH, settings.OSS_WRITE_ROOT, 'bilimili2')
            bucket.put_object_from_file(f"imgs/avatars/{filename}", local_write_path)
            fs.delete(filename)

            # 以前用的默认图片，现在改成新的文件名
            Update_user.update(avatar_path=avatar_read)
        return Response({'msg': '修改成功', 'user': uid}, status=status.HTTP_200_OK)


class UserRegisterViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
    serializer_class = UserRegisterSerializer
    queryset = User.objects.all()

    # 在注册时创建一个用户
    def create(self, request):
        # user = User.objects.create_user(username=request.data['username'], password=request.data['password'])
        serializer = UserRegisterSerializer(data=request.data)
        if User.objects.filter(username=request.data['username']).exists():
            # return Response({'error': 'Username already exists'})
            return Response({'error': '用户名已经存在'}, status=status.HTTP_400_BAD_REQUEST)
        if serializer.is_valid():
            if 'file' in request.FILES:
                filename = request.data['username'] + '.png'
                local_write_path = 'vue/bilimili/src/assets/imgs/avatars/' + filename
                avatar_read = settings.OSS_READ_ROOT + f"/imgs/avatars/{filename}"
                fs = FileSystemStorage(location='vue/bilimili/src/assets/imgs/avatars/')
                fs.save(filename, request.FILES['file'])
                bucket = oss2.Bucket(settings.AUTH, settings.OSS_WRITE_ROOT, 'bilimili2')
                bucket.put_object_from_file(f"imgs/avatars/{filename}", local_write_path)
                fs.delete(filename)
                serializer.validated_data['avatar_path'] = avatar_read
            else:
                serializer.validated_data['avatar_path'] = '/src/assets/imgs/avatars/' + 'default.png'
            serializer.save()
            return Response(serializer.data)
        else:
            return Response(serializer.errors)


class UserLoginViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
    serializer_class = UserLoginSerializer

    def user_exists(self, request, *args, **kwargs):
        user = authenticate(username=kwargs.get('username'), password=kwargs.get('password'))
        if user is not None:
            serializer = UserLoginSerializer(user)
            token, created = Token.objects.get_or_create(user=user)
            return Response({**serializer.data, 'token': token.key})
        else:
            return Response({'error': '用户名或密码错误'}, status=status.HTTP_400_BAD_REQUEST)


def get_data(user, date_op, choice):
    videos = Videos.objects.filter(mup_id=user)
    today = timezone.now().date()

    if date_op == '7日内':
        if choice == 0:
            # 播放量
            return get_week_play(videos)
        elif choice == 1:
            # 点赞量
            return get_week_like(videos)
        elif choice == 2:
            # 收藏量
            return get_week_favor(videos)
        elif choice == 3:
            # 粉丝
            return get_week_fan(user)
        else:
            return get_week_comment(videos)
    elif date_op == '30日内':
        if choice == 0:
            # 播放量
            return get_month_play(videos)
        elif choice == 1:
            return get_month_like(videos)
        elif choice == 2:
            return get_month_favor(videos)
        elif choice == 3:
            return get_month_fan(user)
        else:
            return get_month_comment(videos)
    else:
        if choice == 0:
            return get_year_play(videos)
        elif choice == 1:
            return get_year_like(videos)
        elif choice == 2:
            return get_year_favor(videos)
        elif choice == 3:
            return get_year_fan(user)
        else:
            return get_year_comment(videos)



# today = timezone.now().date()
# date_range_7 = today - timedelta(days=7)
# date_range_30 = today - timedelta(days=30)
# date_range_year = today.replace(year=today.year - 1)

def calculate_time():
    today = timezone.now().date()
    date_range_7 = today - timedelta(days=7)
    date_range_30 = today - timedelta(days=30)
    date_range_year = today.replace(year=today.year - 1)
    return today,date_range_7,date_range_30,date_range_year


# 七天的
def get_week_play(videos):
    today,date_range_7,date_range_30,date_range_year = calculate_time()
    plays = Play.objects.filter(
        video_id__in=videos,
        time__gte=date_range_7,
    ).values('time__date').annotate(count=Sum('count')).order_by('time__date')

    play_counts = {str(date_range_7 + timedelta(days=i)): 0 for i in range(7)}

    for play in plays:
        play_counts[str(play['time__date'])] = play['count']

    return play_counts


def get_week_like(videos):
    today,date_range_7,date_range_30,date_range_year = calculate_time()
    likes = Like.objects.filter(
        video_id__in=videos,
        time__gte=date_range_7,
        is_active=True
    ).values('time__date').annotate(count=Count('*')).order_by('time__date')

    like_counts = {str(date_range_7 + timedelta(days=i)): 0 for i in range(7)}

    for like in likes:
        like_counts[str(like['time__date'])] = like['count']

    return like_counts


def get_week_favor(videos):
    today,date_range_7,date_range_30,date_range_year = calculate_time()

    favors = Favor.objects.filter(
        video_id__in=videos,
        time__gte=date_range_7,
        is_active=True
    ).values('time__date').annotate(count=Count('*')).order_by('time__date')

    favor_counts = {str(date_range_7 + timedelta(days=i)): 0 for i in range(7)}

    for favor in favors:
        favor_counts[str(favor['time__date'])] = favor['count']

    return favor_counts


def get_week_fan(user):
    today,date_range_7,date_range_30,date_range_year = calculate_time()

    fans = Follow.objects.filter(
        mup=user,
        time__gte=date_range_7,
        is_active=True
    ).values('time__date').annotate(count=Count('*')).order_by('time__date')

    fan_counts = {str(date_range_7 + timedelta(days=i)): 0 for i in range(7)}

    for fan in fans:
        fan_counts[str(fan['time__date'])] = fan['count']

    return fan_counts


def get_week_comment(videos):
    today,date_range_7,date_range_30,date_range_year = calculate_time()

    comments = Comment.objects.filter(
        video__in=videos,
        time__gte=date_range_7,
    ).values('time__date').annotate(count=Count('*')).order_by('time__date')

    comment_counts = {str(date_range_7 + timedelta(days=i)): 0 for i in range(7)}

    for comment in comments:
        comment_counts[str(comment['time__date'])] = comment['count']

    return comment_counts


# 三十天的
def get_month_play(videos):
    today,date_range_7,date_range_30,date_range_year = calculate_time()

    plays = Play.objects.filter(
        video_id__in=videos,
        time__gte=date_range_30,
    ).values('time__date').annotate(count=Sum('count')).order_by('time__date')

    play_counts = {}
    start_date = date_range_30

    while start_date <= today:
        end_date = start_date + timedelta(days=2)
        if end_date > today:
            end_date = today
        interval_key = f'{start_date} - {end_date}'
        play_counts[interval_key] = 0
        start_date += timedelta(days=3)

    for play in plays:
        play_date = play['time__date']
        for interval_key in play_counts:
            interval_start, interval_end = interval_key.split(' - ')
            interval_start = datetime.strptime(interval_start, '%Y-%m-%d').date()
            interval_end = datetime.strptime(interval_end, '%Y-%m-%d').date()
            if interval_start <= play_date <= interval_end:
                play_counts[interval_key] += play['count']
                break

    return play_counts


def get_month_like(videos):
    today,date_range_7,date_range_30,date_range_year = calculate_time()

    likes = Like.objects.filter(
        video_id__in=videos,
        time__gte=date_range_30,
        is_active=True
    ).values('time__date').annotate(count=Count('*')).order_by('time__date')

    like_counts = {}
    start_date = date_range_30

    while start_date <= today:
        end_date = start_date + timedelta(days=2)
        if end_date > today:
            end_date = today
        interval_key = f'{start_date} - {end_date}'
        like_counts[interval_key] = 0
        start_date += timedelta(days=3)

    for like in likes:
        like_date = like['time__date']
        for interval_key in like_counts:
            interval_start, interval_end = interval_key.split(' - ')
            interval_start = datetime.strptime(interval_start, '%Y-%m-%d').date()
            interval_end = datetime.strptime(interval_end, '%Y-%m-%d').date()
            if interval_start <= like_date <= interval_end:
                like_counts[interval_key] += like['count']
                break

    return like_counts


def get_month_favor(videos):
    today,date_range_7,date_range_30,date_range_year = calculate_time()

    favors = Favor.objects.filter(
        video_id__in=videos,
        time__gte=date_range_30,
        is_active=True
    ).values('time__date').annotate(count=Count('*')).order_by('time__date')

    favor_counts = {}
    start_date = date_range_30

    while start_date <= today:
        end_date = start_date + timedelta(days=2)
        if end_date > today:
            end_date = today
        interval_key = f'{start_date} - {end_date}'
        favor_counts[interval_key] = 0
        start_date += timedelta(days=3)

    for favor in favors:
        favor_date = favor['time__date']
        for interval_key in favor_counts:
            interval_start, interval_end = interval_key.split(' - ')
            interval_start = datetime.strptime(interval_start, '%Y-%m-%d').date()
            interval_end = datetime.strptime(interval_end, '%Y-%m-%d').date()
            if interval_start <= favor_date <= interval_end:
                favor_counts[interval_key] += favor['count']
                break

    return favor_counts


def get_month_fan(user):
    today,date_range_7,date_range_30,date_range_year = calculate_time()

    fans = Follow.objects.filter(
        mup=user,
        time__gte=date_range_30,
        is_active=True
    ).values('time__date').annotate(count=Count('*')).order_by('time__date')

    fan_counts = {}
    start_date = date_range_30

    while start_date <= today:
        end_date = start_date + timedelta(days=2)
        if end_date > today:
            end_date = today
        interval_key = f'{start_date} - {end_date}'
        fan_counts[interval_key] = 0
        start_date += timedelta(days=3)

    for fan in fans:
        fan_date = fan['time__date']
        for interval_key in fan_counts:
            interval_start, interval_end = interval_key.split(' - ')
            interval_start = datetime.strptime(interval_start, '%Y-%m-%d').date()
            interval_end = datetime.strptime(interval_end, '%Y-%m-%d').date()
            if interval_start <= fan_date <= interval_end:
                fan_counts[interval_key] += fan['count']
                break

    return fan_counts


def get_month_comment(videos):
    today,date_range_7,date_range_30,date_range_year = calculate_time()

    comments = Comment.objects.filter(
        video__in=videos,
        time__gte=date_range_30,
    ).values('time__date').annotate(count=Count('*')).order_by('time__date')

    comment_counts = {}
    start_date = date_range_30

    while start_date <= today:
        end_date = start_date + timedelta(days=2)
        if end_date > today:
            end_date = today
        interval_key = f'{start_date} - {end_date}'
        comment_counts[interval_key] = 0
        start_date += timedelta(days=3)

    for comment in comments:
        comment_date = comment['time__date']
        for interval_key in comment_counts:
            interval_start, interval_end = interval_key.split(' - ')
            interval_start = datetime.strptime(interval_start, '%Y-%m-%d').date()
            interval_end = datetime.strptime(interval_end, '%Y-%m-%d').date()
            if interval_start <= comment_date <= interval_end:
                comment_counts[interval_key] += comment['count']
                break

    return comment_counts


# 一年的
def get_year_play(videos):
    today,date_range_7,date_range_30,date_range_year = calculate_time()

    plays = Play.objects.filter(
        video_id__in=videos,
        time__gte=date_range_year,
    ).values('time__year', 'time__month').annotate(count=Sum('count')).order_by('time__year', 'time__month')

    play_counts = {}
    current_date = date_range_year.replace(day=1)

    while current_date <= today:
        month_key = current_date.strftime('%Y-%m')
        play_counts[month_key] = 0
        if current_date.month == 12:
            current_date = current_date.replace(year=current_date.year + 1, month=1)
        else:
            current_date = current_date.replace(month=current_date.month + 1)

    # 填充播放量
    for play in plays:
        month_key = f"{play['time__year']}-{play['time__month']:02d}"
        play_counts[month_key] = play['count']

    return play_counts


def get_year_like(videos):
    today,date_range_7,date_range_30,date_range_year = calculate_time()

    likes = Like.objects.filter(
        video_id__in=videos,
        time__gte=date_range_year,
        is_active=True
    ).values('time__year', 'time__month').annotate(count=Count('*')).order_by('time__year', 'time__month')

    like_counts = {}
    current_date = date_range_year.replace(day=1)

    while current_date <= today:
        month_key = current_date.strftime('%Y-%m')
        like_counts[month_key] = 0
        if current_date.month == 12:
            current_date = current_date.replace(year=current_date.year + 1, month=1)
        else:
            current_date = current_date.replace(month=current_date.month + 1)

    # 填充播放量
    for like in likes:
        month_key = f"{like['time__year']}-{like['time__month']:02d}"
        like_counts[month_key] = like['count']

    return like_counts


def get_year_favor(videos):
    today,date_range_7,date_range_30,date_range_year = calculate_time()

    favors = Favor.objects.filter(
        video_id__in=videos,
        time__gte=date_range_year,
        is_active=True
    ).values('time__year', 'time__month').annotate(count=Count('*')).order_by('time__year', 'time__month')

    favor_counts = {}
    current_date = date_range_year.replace(day=1)

    while current_date <= today:
        month_key = current_date.strftime('%Y-%m')
        favor_counts[month_key] = 0
        if current_date.month == 12:
            current_date = current_date.replace(year=current_date.year + 1, month=1)
        else:
            current_date = current_date.replace(month=current_date.month + 1)

    # 填充播放量
    for favor in favors:
        month_key = f"{favor['time__year']}-{favor['time__month']:02d}"
        favor_counts[month_key] = favor['count']

    return favor_counts


def get_year_fan(user):
    today,date_range_7,date_range_30,date_range_year = calculate_time()

    fans = Follow.objects.filter(
        mup=user,
        time__gte=date_range_year,
        is_active=True
    ).values('time__year', 'time__month').annotate(count=Count('*')).order_by('time__year', 'time__month')

    fan_counts = {}
    current_date = date_range_year.replace(day=1)

    while current_date <= today:
        month_key = current_date.strftime('%Y-%m')
        fan_counts[month_key] = 0
        if current_date.month == 12:
            current_date = current_date.replace(year=current_date.year + 1, month=1)
        else:
            current_date = current_date.replace(month=current_date.month + 1)

    # 填充播放量
    for fan in fans:
        month_key = f"{fan['time__year']}-{fan['time__month']:02d}"
        fan_counts[month_key] = fan['count']

    return fan_counts


def get_year_comment(videos):
    today,date_range_7,date_range_30,date_range_year = calculate_time()

    comments = Comment.objects.filter(
        video__in=videos,
        time__gte=date_range_year,
    ).values('time__year', 'time__month').annotate(count=Count('*')).order_by('time__year', 'time__month')

    comment_counts = {}
    current_date = date_range_year.replace(day=1)

    while current_date <= today:
        month_key = current_date.strftime('%Y-%m')
        comment_counts[month_key] = 0
        if current_date.month == 12:
            current_date = current_date.replace(year=current_date.year + 1, month=1)
        else:
            current_date = current_date.replace(month=current_date.month + 1)

    # 填充播放量
    for comment in comments:
        month_key = f"{comment['time__year']}-{comment['time__month']:02d}"
        comment_counts[month_key] = comment['count']

    return comment_counts


def time_format(ave_progress):
    hours = int(ave_progress // 3600)
    minutes = int((ave_progress % 3600) // 60)
    seconds = int(ave_progress % 60)
    if hours > 0:
        time_str = f"{hours}:{minutes:02}:{seconds:02}"
    else:
        time_str = f"{minutes:02}:{seconds:02}"
    return time_str


def serialize_data(video, fans):
    ave_progress = Play.objects.filter(video=video).aggregate(ave=Avg('progress'))['ave']
    if ave_progress is None:
        ave_progress = 0

    play_count = Play.objects.filter(video=video).aggregate(sum_count=Sum('count'))['sum_count']
    if play_count is None: play_count = 0
    like_count = Like.objects.filter(video_id=video).filter(is_active=True).count()
    if like_count is None: like_count = 0
    play_num = Play.objects.filter(video_id=video).count()
    if play_num is None: play_num = 0
    favor_count = Favor.objects.filter(video_id=video).filter(is_active=True).count()
    if favor_count is None: favor_count = 0
    max_repeat = Play.objects.filter(video_id=video).aggregate(max_repeat=Max('count'))['max_repeat']
    if max_repeat is None: max_repeat = 0
    fan_play_count = Play.objects.filter(video_id=video).filter(user__in=fans).count()
    if fan_play_count is None: fan_play_count = 0
    fan_count = fans.count()
    if fan_count is None: fan_count = 0
    fan_like_count = Like.objects.filter(video_id=video).filter(is_active=True).filter(user_id__in=fans).count()
    if fan_like_count is None: fan_like_count = 0

    like_rate = '0%' if play_num == 0 else str(round(100 * like_count / play_num, 2)) + '%'
    favor_rate = '0%' if play_num == 0 else str(round(100 * favor_count / play_num, 2)) + '%'
    fan_play_rate = '0%' if fan_count == 0 else str(round(100 * fan_play_count / fan_count, 2)) + '%'
    fan_like_rate = '0%' if fan_count == 0 else str(round(100 * fan_like_count / fan_count, 2)) + '%'
    traveler_play_rate = '0%' if play_num == 0 else str(round(100 * (1 - fan_play_count / play_num), 2)) + '%'

    data = {
        'vid': video.vid,
        'title': video.title,
        'date': video.update_time.date(),
        'time': video.update_time.time().replace(microsecond=0),
        'cover_path': video.cover_path,
        'play_count': play_count,
        'like_count': like_count,
        'like_rate': like_rate,
        'favor_count': favor_count,
        'favor_rate': favor_rate,
        'max_repeat': max_repeat,
        'fan_play_rate': fan_play_rate,
        'fan_like_rate': fan_like_rate,
        'traveler_play': traveler_play_rate,
        'ave_progress': time_format(ave_progress),
        'ave_pro_rate': str(round(100 * ave_progress / video.duration, 2)) + '%'
    }
    return data
